#pragma once

#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <cstdlib>
#include <functional>

using namespace std;

using func_t = function<string(const string &, const string&, uint16_t&)>;
// 类似于
// typedef function<string(const string&)> func_t;

Log lg;


enum
{
    SOCKET_ERR = 1,
    BIND_ERR = 2
};

uint16_t defaultport = 8080;
string defaultip = "0.0.0.0";

class UdpServer
{
public:
    UdpServer(uint16_t port = defaultport, const string &ip = defaultip)
        : _port(port), _ip(ip), _sockfd(0),_isrunning(false)
    {
    }

    void Init()
    {
        // 1.创建udp socket
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0) // 创建套接字失败
        {
            lg.operator()(Fatal, "sockfd create error: %d", _sockfd);
            exit(SOCKET_ERR);
        }
        lg(Info, "socket create success, sockfd: %d", _sockfd); // 3

        // 2.绑定端口号
        struct sockaddr_in local;
        bzero(&local, sizeof(local)); // 清空结构体
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);//需要保证我的端口号是网络字节序列(大端),因为该端口号是要给对方发送的
        //1.string -> uint_32_t
        //2.必须是网络序列的
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        //local.sin_addr.s_addr = INADDR_ANY; // 任意ip地址


        int n = bind(_sockfd, (const struct sockaddr*)&local, sizeof(local));
        if(n < 0) //绑定失败
        {
            lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info,"bind create success"); 
    }

    void Run(func_t func) 
    {
        // 服务器一直在运行
        _isrunning = true;
        char inbuffer[1024];
        while(_isrunning)
        {
            // 获取用户端的ip,端口号,用户发送的请求
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(_sockfd, inbuffer, 1023, 0, (struct sockaddr*)&client, &len);
            if(n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[n] = '\0'; //当作字符串来看

            // 拿到用户端的端口号和ip地址
            uint16_t clientport = ntohs(client.sin_port);
            string clientip = inet_ntoa(client.sin_addr);

            // 数据的处理
            string info = inbuffer;
            string echo_string = func(info, clientip, clientport);
            // cout << echo_string << endl;
            // 数据发送给用户
            sendto(_sockfd, echo_string.c_str(), echo_string.size(),0,(const struct sockaddr*)&client, len);
        }
    }
    ~UdpServer() 
    {
        if(_sockfd > 0)
            close(_sockfd);
    }

private:
    int _sockfd;    // 网络文件描述符
    string _ip;     // 服务器的ip  任意地址绑定
    uint16_t _port; // 服务器进程的端口号
    bool _isrunning; // 服务器是否在运行
};


